﻿using System.Collections.Generic;
using System.Linq;
using Autodesk.AutoCAD.Geometry;

namespace AutoCADDotNetLibrary
{
    /// <summary>
    /// 点的扩展
    /// </summary>
    public static class PointExtention
    {
        /// <summary>
        /// 点相等的差值
        /// </summary>
        public const double Toleranct = 1e-7;//0.00000001;

        /// <summary>
        /// 中点
        /// </summary>
        /// <param name="point">2维点</param>
        /// <param name="point2d">2维点</param>
        /// <returns>中点</returns>
        public static Point2d Middle(this Point2d point, Point2d point2d)
        {
            return new Point2d((point2d.X + point.X) / 2, (point2d.Y + point.Y) / 2);
        }

        /// <summary>
        /// 中点
        /// </summary>
        /// <param name="point">3维点</param>
        /// <param name="point3d">3维点</param>
        /// <returns>中点</returns>
        public static Point3d Middle(this Point3d point, Point3d point3d)
        {
            return new Point3d((point3d.X + point.X) / 2, (point3d.Y + point.Y) / 2, (point3d.Z + point.Z) / 2);
        }

        /// <summary>
        /// 三维点转二维点
        /// </summary>
        /// <param name="point3d">3维点</param>
        /// <returns>2维点</returns>
        public static Point2d ToPoint2d(this Point3d point3d)
        {
            return new Point2d(point3d.X, point3d.Y);
        }

        /// <summary>
        /// 二维点转三维点
        /// </summary>
        /// <param name="point2d">2维点</param>
        /// <param name="z">z</param>
        /// <returns>3维点</returns>
        public static Point3d ToPoint3d(this Point2d point2d, double z = 0)
        {
            return new Point3d(point2d.X, point2d.Y, z);
        }

        /// <summary>
        /// 三维点是否相等
        /// </summary>
        /// <param name="point">3维点</param>
        /// <param name="point3d">3维点</param>
        /// <param name="toleranct">容差</param>
        /// <returns>是否相等</returns>
        public static bool IsEqual(this Point3d point, Point3d point3d, double toleranct = Toleranct)
        {
            return point3d.DistanceTo(point) <= toleranct;
        }

        /// <summary>
        /// 二维点是否相等
        /// </summary>
        /// <param name="point">2维点</param>
        /// <param name="point2d">2维点</param>
        /// <param name="toleranct">容差</param>
        /// <returns>是否相等</returns>
        public static bool IsEqual(this Point2d point, Point2d point2d, double toleranct = Toleranct)
        {
            return point2d.GetDistanceTo(point) <= toleranct;
        }

        /// <summary>
        /// 点是否在线上
        /// </summary>
        /// <param name="point">判断点</param>
        /// <param name="pt1">边的一点</param>
        /// <param name="pt2">边的另一点</param>
        /// <returns>是否在线上</returns>
        public static bool IsPtOnPtsBetween(this Point2d point, Point2d pt1, Point2d pt2)
        {
            LineSegment2d l = new LineSegment2d(pt1, pt2);
            return l.IsOn(point);
        }

        /// <summary>
        /// 点集的线性回归方程Ax+By+C=0,返回A,B,C
        /// </summary>
        /// <param name="source">点集</param>
        /// <returns>A,B,C</returns>
        public static double[] LinearRegression(IEnumerable<Point2d> source)
        {
            double xAverage = source.Average(x => x.X);
            double yAverage = source.Average(x => x.Y);

            double bfz = source.Sum(x => x.X * x.Y) - source.Count() * xAverage * yAverage;
            double bfm = source.Sum(x => x.X * x.X) - source.Count() * xAverage * xAverage;
            return new double[] { -bfz, bfm, bfz * xAverage - bfm * yAverage };
        }

        /// <summary>
        /// 依据线性回归的方向进行排序（C=B*x-A*y）
        /// </summary>
        /// <param name="source">点集</param>
        /// <returns>排序后点集</returns>
        public static IEnumerable<Point2d> SortByLinearRegression(IEnumerable<Point2d> source)
        {
            double[] v = LinearRegression(source);

            return source.OrderBy(x => v[1] * x.X - v[0] * x.Y);
        }
    }
}
